import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Upload as AntdUpload, Icon } from 'antd';
import axios from 'axios';
import { Base64 } from 'js-base64';

import styles from './style.scss';
import request from './request';
import Button from '@components/Button';

export default class FileUpload extends Component {
    static propTypes = {
        defaultValue: PropTypes.string,
        value: PropTypes.string,
        fileType: PropTypes.string,
        disabled: PropTypes.bool,
        onChange: PropTypes.func,
        onDelete: PropTypes.func,
        onBeforeUploadAbort: PropTypes.func,
    };

    static defaultProps = {
        disabled: false,
        fileType: 'document',
        onChange: () => undefined,
        onDelete: () => undefined,
        onBeforeUploadAbort: () => undefined,
    };

    constructor(props) {
        super(props);
        const {
            value,
            defaultValue,
        } = props;
        let files = value || defaultValue;
        if (files) {
            try {
                files = JSON.parse(files);
            } catch (err) {
            }
            if (!Array.isArray(files)) {
                files = [files];
            }
        }
        this.state = {
            files: files || [],
            error: null,
        };
        this.tokenKey = `file_upload_token_${props.fileType}`;
        this.targetKey = 'file_upload_url';
    }

    componentWillReceiveProps(nextProps) {
        if ('value' in nextProps) {
            let files = nextProps.value;
            if (files) {
                try {
                    files = JSON.parse(files);
                } catch (err) {
                }
                if (!Array.isArray(files)) {
                    files = [files];
                }
            }
            this.setState({
                files: files || [],
            });
        }
    }

    onBeforeUpload = (file, fileList) => {
        const { accept, maxSize, onBeforeUploadAbort } = this.props;
        const { name, size } = file;
        this.setState({
            error: null,
        });
        return new Promise(async (resolve, reject) => {
            if (this.state.files && this.state.files.filter(item => item.name === name)[0]) {
                onBeforeUploadAbort(4, file, fileList);
                this.setState({
                    error: '已存在该文件',
                });
                return reject();
            }
            if (name.length > 100) {
                onBeforeUploadAbort(3, file, fileList);
                this.setState({
                    error: '文件名不能超过100个字符',
                });
                return reject();
            }
            if (accept) {
                let arrAccept = accept.toLowerCase().split(',');
                const ext = name.substr(name.lastIndexOf('.')).toLowerCase();
                if (arrAccept.indexOf(ext) === -1) {
                    onBeforeUploadAbort(1, file, fileList);
                    this.setState({
                        error: '不支持上传该类型的文件',
                    });
                    return reject();
                }
            }
            if (maxSize > 0 && size > maxSize) {
                onBeforeUploadAbort(2, file, fileList);
                let humanReadableMaxSize;
                if (maxSize >= 1 << 20) {
                    humanReadableMaxSize = (maxSize >> 20) + 'M';
                } else if (maxSize >= 1 << 10) {
                    humanReadableMaxSize = (maxSize >> 10) + 'K';
                } else {
                    humanReadableMaxSize = maxSize + 'B';
                }
                this.setState({
                    error: `文件不能超过${humanReadableMaxSize}`,
                });
                return reject();
            }
            let needGetNewToken = false;
            let token = sessionStorage.getItem(this.tokenKey);
            let uploadUrl = sessionStorage.getItem(this.targetKey);
            if (!token || !uploadUrl) {
                needGetNewToken = true;
            } else {
                try {
                    const payload = JSON.parse(Base64.decode(token.split('.')[1] || ''));
                    if (!payload || payload.exp <= (Date.now() / 1000)) {
                        needGetNewToken = true;
                    }
                } catch (err) {
                    needGetNewToken = true;
                }
            }
            if (needGetNewToken) {
                const res = await axios.get(`/upload-token?type=${this.props.fileType}`, {
                    headers: {
                        'X-Requested-With': 'XMLHttpRequest',
                        'Cache-Control': 'no-cache',
                        'Pragma': 'no-cache',
                    }
                }).then(res => res.data).catch(err => null);
                if (res && res.data) {
                    token = res.data.token;
                    uploadUrl = res.data.host + '/api/upload';
                }
                if (!token) {
                    this.setState({
                        error: '上传失败，获取资源服务器校验信息错误',
                    });
                    return reject();
                }
                sessionStorage.setItem(this.tokenKey, token);
                sessionStorage.setItem(this.targetKey, uploadUrl);
            }
            resolve();
        });

    };

    onChange = info => {
        const { onChange } = this.props;
        const file = info.file;
        if (!file) {
            return;
        }
        if (file.status === 'uploading' && !this.state.isUploading) {
            this.setState({
                isUploading: true,
            });
        } else if (file.status === 'done') {
            this.setState({
                isUploading: false,
            });
        } else if (file.status === 'error') {
            this.setState({
                isUploading: false,
                error: '上传失败，资源服务器返回错误'
            });
            sessionStorage.removeItem(this.tokenKey);
            sessionStorage.removeItem(this.targetKey);
        }
        onChange(info);
    };

    onDelete = (idx, evt) => {
        const { onDelete } = this.props;
        onDelete(idx, evt);
    };

    processRequestData = file => {
        return {
            key: 'file',
            token: sessionStorage.getItem(this.tokenKey),
            redirect: 'none',
            file: file
        };
    };

    render() {
        let {
            description,
            count,
            disabled,
            accept,
        } = this.props;
        const {
            files,
            error,
        } = this.state;
        const len = files && files.length || 0;
        const isDisabled = disabled || count <= len;
        return (
            <div>
                <div className={styles.fileUploadOperationBox}>
                    <AntdUpload
                        accept={accept}
                        disabled={isDisabled}
                        beforeUpload={this.onBeforeUpload}
                        onChange={this.onChange}
                        showUploadList={false}
                        data={this.processRequestData}
                        customRequest={request}
                    >
                        <Button type="E" disabled={isDisabled}><Icon type="upload" style={{ marginRight: 5, fontSize: 13 }} />上传文档</Button>
                    </AntdUpload>
                    <span className={styles.fileUploadDesc}>{description}</span>
                    <div className={styles.fileUploadErr}>{error}</div>
                </div>
                {
                    files && <div className={styles.uploadedFileList}>
                        {
                            files.map((file, idx) => {
                                const {
                                    name,
                                    download,
                                } = file;
                                return (
                                    <div className={styles.uploadedFile} key={download} title={name}>
                                        <div className={styles.uploadedFileName}>
                                            <a href={`${download}?name=${name}`} target="_blank" >
                                                <Icon type="paper-clip" />
                                                {name}
                                            </a>
                                        </div>
                                        <a
                                            className={styles.btnDeleteUploadedFile}
                                            onClick={evt => {
                                                this.onDelete(idx, evt);
                                            }}
                                        >删除</a>
                                    </div>
                                );
                            })
                        }
                    </div>
                }
            </div>
        );
    }
}
